package com.zyw.net.supports;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.zyw.net.exception.HttpClientConnectException;
import com.zyw.net.exception.HttpClientReadtimeoutException;
import com.zyw.net.http.HttpClient;
import com.zyw.net.http.HttpParams;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.exception.ExceptionUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.util.concurrent.Callable;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;


/**
 * @author zhangyw
 * @ClassName BaseApi
 * @Description
 * @date 16/11/24 15:59
 */
public abstract class BaseApi {

    protected static Logger logger = LoggerFactory.getLogger(BaseApi.class);

    /**
     * 直接 实例化， 类加载时，减少使用时创建http耗费的时间
     */
    private static HttpClient httpClient =
            HttpClient.newHttpClient()
                    .connectTimeout(1000) // 默认 1s 连接超时 (connectTimeout)
                    .readTimeout(2000); // 默认 2s 读取超时

    private static ExecutorService executor = Executors.newScheduledThreadPool(10);

    protected static String get(String url) throws Exception {
        return get(url, httpClient.defaultCallback);
    }

    protected static String get(String url, HttpClient.ResponseCallback callback) {
        return get(url, HttpParams.create(), callback);
    }

    protected static String get(String url, HttpParams params) {
        return get(url, params, httpClient.defaultCallback);
    }

    protected static String get(String url, HttpParams params, HttpClient.ResponseCallback callback) {
        long start = System.currentTimeMillis();
        String res = null;
        try {
            res = httpClient.get(url, params, callback);
        } catch (HttpClientConnectException | HttpClientReadtimeoutException e) {
            logger.warn(e.getMessage());
//            throw e;
        } catch (Exception e) {
            logger.error(ExceptionUtils.getStackTrace(e));
        }
        logger.info("HTTP GET {},params:{},success:{},res:{},cost:{}ms", url, params.toString(), res != null, res != null ? res.replace("\n", "") : "", System.currentTimeMillis() - start);
        return res;
    }

    protected static <T extends Response> T get(String url, HttpParams params, Class<T> cls) {
        return get(url, params, cls, httpClient.defaultCallback);
    }

    protected static <T extends Response> T get(String url, HttpParams params, Class<T> cls, HttpClient.ResponseCallback callback) {
        long start = System.currentTimeMillis();
        T response = null;
        String res = null;
        boolean success = false;
        try {
            res = httpClient.get(url, params, callback);
            if (StringUtils.isNotEmpty(res)) {
                response = JSON.parseObject(res, cls);
                success = response.isSuccess();
            }

//            if (!success) {
//                throw new RequestException(response.getMsg());
//            }
        } catch (HttpClientConnectException | HttpClientReadtimeoutException e) {
            logger.warn(e.getMessage());
//            throw e;
        } catch (Exception e) {
            logger.error(ExceptionUtils.getStackTrace(e));
        } finally {
            logger.info("HTTP GET {},params:{},success:{},res:{},cost:{}ms",
                    url,
                    params.toString(),
                    success, res != null ? res.replace("\n", "") : "",
                    System.currentTimeMillis() - start);
        }

        if (response == null) {
            try {
                response = cls.newInstance();
            } catch (InstantiationException | IllegalAccessException e) {
                logger.error(ExceptionUtils.getStackTrace(e));
            }
        }
        return response;
    }

    protected static <T extends Response> T post(String url, HttpParams params, Class<T> cls) {
        return post(url, params, cls, null);
    }

    protected static <T extends Response> T post(String url, HttpParams params, Class<T> cls, HttpClient.ResponseCallback callback) {
        long start = System.currentTimeMillis();
        T response = null;
        String res = null;
        boolean success = false;
        try {
            res = httpClient.post(url, params, callback);
            if (StringUtils.isNotEmpty(res)) {
                response = JSON.parseObject(res, cls);
                success = response.isSuccess();
//                if (!success) {
//                    throw new RequestException(response.getMsg());
//                }
            }
        } catch (HttpClientConnectException | HttpClientReadtimeoutException e) {
            logger.warn(e.getMessage());
//            throw e;
        } catch (Exception e) {
            logger.error(ExceptionUtils.getStackTrace(e));
        } finally {
            logger.info("HTTP POST {},params:{},success:{},res:{},cost:{}ms",
                    url,
                    params.toString(),
                    success,
                    res != null ? res.replaceAll("\n", "") : "",
                    System.currentTimeMillis() - start);
        }

        if (response == null) {
            try {
                response = cls.newInstance();
            } catch (InstantiationException | IllegalAccessException e) {
                logger.error(ExceptionUtils.getStackTrace(e));
            }
        }
        return response;
    }

    protected static String post(String url, HttpParams params) {
        return post(url, params, httpClient.defaultCallback);
    }

    protected static String post(String url, HttpParams params, HttpClient.ResponseCallback callback) {
        long start = System.currentTimeMillis();
        String res = null;
        try {
            res = httpClient.post(url, params, callback);
        } catch (HttpClientConnectException | HttpClientReadtimeoutException e) {
            logger.warn(e.getMessage());
//            throw e;
        } catch (Exception e) {
            logger.error(ExceptionUtils.getStackTrace(e));
        }
        logger.info("HTTP POST {},params:{},success:{},res:{},cost:{}ms", url, params.toString(), res != null, res != null ? res.replace("\n", "") : "", System.currentTimeMillis() - start);
        return res;
    }

    protected static JSONObject parseResult(String result) {
        if (result == null) return null;

        JSONObject jsonObject = JSON.parseObject(result);
        String code = jsonObject.get("code").toString();
        if ("1".equals(code))
            return jsonObject.getJSONObject("data");
        else {
//            logger.debug("异常返回数据:{}", result);
//            throw new RequestException(String.valueOf(jsonObject.get("msg")));
            return null;
        }
    }

    protected static JSONArray parseListResult(String result) {
        if (result == null) return null;

        JSONObject jsonObject = JSON.parseObject(result);
        String code = jsonObject.get("code").toString();
        if ("1".equals(code))
            return jsonObject.getJSONArray("data");
        else {
//            logger.debug("异常返回数据:{}", result);
//            throw new RequestException(String.valueOf(jsonObject.get("msg")));
            return null;
        }
    }

    protected static String buildRequestUrl(String... urls) {
        StringBuffer sb = new StringBuffer();
        for (int i = 0; i < urls.length; i++) {
            String url = urls[i];
            // 如果是最后一个，则不去掉末尾的"/" 符
            if (url.endsWith("/") && (i < urls.length - 1)) {
                url = url.substring(0, url.lastIndexOf("/"));
            }
            sb.append(url);
        }
        return sb.toString();
    }

    protected static <T> Future<T> submitTask(Callable<T> task) {
        return executor.submit(task);
    }

    protected static <T> Future<T> submit(Callable<T> task) {
        return executor.submit(task);
    }

    protected static <T> Future<T> submit(Runnable task, T result) {
        return executor.submit(task, result);
    }

    protected static Future<?> submit(Runnable task) {
        return executor.submit(task);
    }

    protected static void execute(Runnable command) {
        executor.execute(command);
    }
}
